package com.niiwoo.civet.trade.service.local.plan;

import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dto.BorrowerRepaymentDTO;
import com.niiwoo.civet.trade.dto.RateConfigDTO;
import com.niiwoo.civet.trade.dto.common.BuildRepaymentDTO;
import com.niiwoo.civet.trade.dto.request.loan.RepaymentPlanDTO;
import com.niiwoo.civet.trade.enums.PeriodUnitEnum;
import com.niiwoo.civet.trade.enums.RepayStatusEnum;
import com.niiwoo.civet.trade.enums.RepaymentTypeEnum;
import com.niiwoo.tripod.provider.exception.NoSuchEnumValueException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
public class BorrowerInvestorRepaymentContext {

	@Autowired
	private List<BorrowerInvestorRepaymentManager> borrowerInvestorRepaymentManager;

	/**
	 *
	 * @param repaymentType
	 * @param amount
	 * @param yearRate
	 * @param deadline
	 * @param periodUnitEnum
	 * @param startDate
	 * @param leastCalculateInterestDays
	 * @return
	 */
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(RepaymentTypeEnum repaymentType, BigDecimal amount,
														   BigDecimal yearRate, Integer deadline, PeriodUnitEnum periodUnitEnum, Date startDate, Integer leastCalculateInterestDays) {
		for (BorrowerInvestorRepaymentManager manager : borrowerInvestorRepaymentManager) {
			if (manager.supports(getInterestAccrualEnum(repaymentType, leastCalculateInterestDays))) {
				return manager.getBorrowerRepaymentPlan(amount, yearRate,
						deadline, periodUnitEnum, startDate, leastCalculateInterestDays);

			}
		}
		throw new NoSuchEnumValueException("RepaymentTypeEnum:" + repaymentType);
	}

	/**
	 * 根据还款方式、年利率、金额、期限、期限单位、管理费率、担保费率和费率配置信息生成还款计划
	 * 开始如期为null使用当前日期
	 * 
	 * @param buildRepaymentDTO
	 *            标的信息
	 * @param rateConfigDTOList
	 *            费率配置
	 * @return
	 */
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(BuildRepaymentDTO buildRepaymentDTO, List<RateConfigDTO> rateConfigDTOList) {
		buildRepaymentDTOCheck(buildRepaymentDTO);
		for (BorrowerInvestorRepaymentManager manager : borrowerInvestorRepaymentManager) {
			if (manager.supports(getInterestAccrualEnum(buildRepaymentDTO.getRepaymentType(), buildRepaymentDTO.getLeastCalculateInterestDays()))) {
				return manager.getBorrowerRepaymentPlan(buildRepaymentDTO, rateConfigDTOList);

			}
		}
		throw new NoSuchEnumValueException("RepaymentTypeEnum:" + buildRepaymentDTO.getRepaymentType());
	}
	
	public BorrowerRepaymentDTO buildBorrowerRepaymentPlan(Project project, List<ProjectRate> projectRateList) {
		ProjectBorrowerSummary projectBorrowerSummary = buildBorrowerSummary(project);
		for (BorrowerInvestorRepaymentManager manager : borrowerInvestorRepaymentManager) {
			if (manager.supports(getInterestAccrualEnum(RepaymentTypeEnum.enumOf(project.getRepaymentType()), project.getLeastCalculateInterestDays()))) {
				return manager.buildBorrowerRepaymentPlan(project, projectBorrowerSummary, projectRateList);
			}
		}
		throw new NoSuchEnumValueException("RepaymentTypeEnum:" + RepaymentTypeEnum.enumOf(project.getRepaymentType()));
	}

	public List<ProjectInvestorPlan> buildInvestorRepaymentPlan(Project project,
			List<ProjectInvestOrder> projectInvestOrderList, BorrowerRepaymentDTO borrowerRepaymentDTO) {
		for (BorrowerInvestorRepaymentManager manager : borrowerInvestorRepaymentManager) {
			if (manager.supports(getInterestAccrualEnum(RepaymentTypeEnum.enumOf(project.getRepaymentType()), project.getLeastCalculateInterestDays()))) {
				return manager.buildInvestorRepaymentPlan(project, projectInvestOrderList, borrowerRepaymentDTO);
			}
		}
		throw new NoSuchEnumValueException("RepaymentTypeEnum:" + RepaymentTypeEnum.enumOf(project.getRepaymentType()));
	}

	private void buildRepaymentDTOCheck(BuildRepaymentDTO buildRepaymentDTO) {
		Assert.notNull(buildRepaymentDTO, "build plan buildRepaymentDTO is null.");
		Assert.notNull(buildRepaymentDTO.getRepaymentType(), "build plan buildRepaymentDTO repaymentType is null.");
	}

	private ProjectBorrowerSummary buildBorrowerSummary(Project project) {
		ProjectBorrowerSummary projectBorrowerSummary = new ProjectBorrowerSummary();
		projectBorrowerSummary.setProjectId(project.getProjectId());
		projectBorrowerSummary.setProjectTitle(project.getTitle());
		projectBorrowerSummary.setBorrowerUserId(project.getBorrowUserId());
		projectBorrowerSummary.setCurrentPeriod(1);
		projectBorrowerSummary.setPenaltyRate(project.getPenaltyRate());
		projectBorrowerSummary.setPublishTime(project.getPublishTime());
		projectBorrowerSummary.setRepayStatus(RepayStatusEnum.NORMAL.getCode());
		projectBorrowerSummary.setChannelCode(project.getChannelCode());
		projectBorrowerSummary.setCreateTime(new Date());
		projectBorrowerSummary.setUpdateTime(new Date());
		return projectBorrowerSummary;
	}

	private InterestAccrualEnum getInterestAccrualEnum(RepaymentTypeEnum repaymentType, Integer leastCalculateInterestDays) {
		if(leastCalculateInterestDays != null && leastCalculateInterestDays != 0){
			return InterestAccrualEnum.CALCULATE_INTEREST_BY_DAY;
		} else {
			switch (repaymentType) {
				case REPAY_PRINCIPAL_INTEREST_AT_TERM:
					return InterestAccrualEnum.REPAY_PRINCIPAL_INTEREST_AT_TERM;
				case AVERAGE_CAPITAL_PLUS_INTEREST:
					return InterestAccrualEnum.AVERAGE_CAPITAL_PLUS_INTEREST;

				case MONTHLY_INTEREST_PAYMENT_DUE:
					return InterestAccrualEnum.MONTHLY_INTEREST_PAYMENT_DUE;

				default:
					throw new NoSuchEnumValueException("RepaymentTypeEnum:" + repaymentType);
			}
		}
	}

}
